package org.gdstash.db;

import org.gdstash.file.ARCDecompress;
import org.gdstash.file.ARCList;
import org.gdstash.file.ARZDecompress;
import org.gdstash.util.GDConstants;
import org.gdstash.util.GDMsgFormatter;
import org.gdstash.util.GDMsgLogger;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

public class DBEngineTagText {
    private static final String TABLE_NAME = "GDC_TAGTEXT";
    private static final String PREFIX_MASTERY_TAG = "tagSkillClassName";
    private static final int MAX_MASTERIES = 80;
    private static final int ROW_TAG = 1;
    private static final int ROW_TEXT_MS = 2;
    private static final int ROW_TEXT_FS = 3;
    private static final int ROW_TEXT_NS = 4;
    private static final int ROW_TEXT_MP = 5;
    private static final int ROW_TEXT_FP = 6;
    private static final int ROW_TEXT_NP = 7;
    private static ConcurrentHashMap<String, DBEngineTagText> hashBuffer;
    private static List<DBEngineTagText> texts;
    private String tag;
    private String textMS;
    private String textFS;
    private String textNS;
    private String textMP;
    private String textFP;
    private String textNP;

    public DBEngineTagText() {
        this.tag = null;
        this.textMS = null;
        this.textFS = null;
        this.textNS = null;
        this.textMP = null;
        this.textFP = null;
        this.textNP = null;
    }

    public DBEngineTagText(final String tag, final String text) {
        this.tag = tag;
        final String[] genders = ARZDecompress.getGenderTexts(text);
        this.textMS = genders[0];
        this.textFS = genders[1];
        this.textNS = genders[2];
        this.textMP = genders[3];
        this.textFP = genders[4];
        this.textNP = genders[5];
    }

    static {
        DBEngineTagText.hashBuffer = new ConcurrentHashMap<String, DBEngineTagText>();
        DBEngineTagText.texts = new LinkedList<DBEngineTagText>();
    }

    private static List<DBEngineTagText> wrap(final ResultSet rs) throws SQLException {
        final LinkedList<DBEngineTagText> list = new LinkedList<DBEngineTagText>();
        while (rs.next()) {
            final DBEngineTagText tt = new DBEngineTagText();
            tt.tag = rs.getString(1);
            final DBEngineTagText buff = DBEngineTagText.hashBuffer.get(tt.tag);
            if (buff != null) {
                list.add(buff);
            } else {
                tt.textMS = rs.getString(2);
                tt.textFS = rs.getString(3);
                tt.textNS = rs.getString(4);
                tt.textMP = rs.getString(5);
                tt.textFP = rs.getString(6);
                tt.textNP = rs.getString(7);
                if (tt.textMS != null) {
                    final ByteBuffer buffer = StandardCharsets.UTF_8.encode(tt.textMS);
                    final String utf8 = StandardCharsets.UTF_8.decode(buffer).toString();
                    tt.textMS = utf8;
                }
                if (tt.textFS != null) {
                    final ByteBuffer buffer = StandardCharsets.UTF_8.encode(tt.textFS);
                    final String utf8 = StandardCharsets.UTF_8.decode(buffer).toString();
                    tt.textFS = utf8;
                }
                if (tt.textNS != null) {
                    final ByteBuffer buffer = StandardCharsets.UTF_8.encode(tt.textNS);
                    final String utf8 = StandardCharsets.UTF_8.decode(buffer).toString();
                    tt.textNS = utf8;
                }
                if (tt.textMP != null) {
                    final ByteBuffer buffer = StandardCharsets.UTF_8.encode(tt.textMP);
                    final String utf8 = StandardCharsets.UTF_8.decode(buffer).toString();
                    tt.textMP = utf8;
                }
                if (tt.textFP != null) {
                    final ByteBuffer buffer = StandardCharsets.UTF_8.encode(tt.textFP);
                    final String utf8 = StandardCharsets.UTF_8.decode(buffer).toString();
                    tt.textFP = utf8;
                }
                if (tt.textNP != null) {
                    final ByteBuffer buffer = StandardCharsets.UTF_8.encode(tt.textNP);
                    final String utf8 = StandardCharsets.UTF_8.decode(buffer).toString();
                    tt.textNP = utf8;
                }
                list.add(tt);
                DBEngineTagText.hashBuffer.put(tt.tag, tt);
            }
        }
        return list;
    }

    public static void clearBuffer() {
        DBEngineTagText.hashBuffer.clear();
    }

    public static void createTable() throws SQLException {
        final String dropTable = "DROP TABLE GDC_TAGTEXT";
        final String createTable = "CREATE TABLE GDC_TAGTEXT (TAG     VARCHAR(64), TEXT_MS VARCHAR(256), TEXT_FS VARCHAR(256), TEXT_NS VARCHAR(256), TEXT_MP VARCHAR(256), TEXT_FP VARCHAR(256), TEXT_NP VARCHAR(256), PRIMARY KEY (TAG))";
        try (final Connection conn = GDDBData.getConnection()) {
            final boolean auto = conn.getAutoCommit();
            conn.setAutoCommit(false);
            try (final Statement st = conn.createStatement()) {
                if (GDDBUtil.tableExists(conn, "GDC_TAGTEXT")) {
                    st.execute(dropTable);
                }
                st.execute(createTable);
                st.close();
                conn.commit();
            } catch (SQLException ex) {
                conn.rollback();
                final Object[] args = {"GDC_TAGTEXT"};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_CREATE_TABLE", args);
                GDMsgLogger.addError(msg);
                throw ex;
            } finally {
                conn.setAutoCommit(auto);
            }
        }
    }

    public static void delete(final String tag) throws SQLException {
        final String deleteEntry = "DELETE FROM GDC_TAGTEXT WHERE TAG = ?";
        try (final Connection conn = GDDBData.getConnection()) {
            final boolean auto = conn.getAutoCommit();
            conn.setAutoCommit(false);
            try (final PreparedStatement ps = conn.prepareStatement(deleteEntry)) {
                ps.setString(1, tag);
                ps.executeUpdate();
                ps.close();
                conn.commit();
            } catch (SQLException ex) {
                conn.rollback();
            } finally {
                conn.setAutoCommit(auto);
            }
        } catch (SQLException ex2) {
        }
    }

    public String getTag() {
        return this.tag;
    }

    public String getText(final int genderID) {
        String s = null;
        switch (genderID) {
            case 0: {
                s = this.textMS;
                break;
            }
            case 1: {
                s = this.textFS;
                break;
            }
            case 2: {
                s = this.textNS;
                break;
            }
            case 3: {
                s = this.textMP;
                break;
            }
            case 4: {
                s = this.textFP;
                break;
            }
            case 5: {
                s = this.textNP;
                break;
            }
            default: {
                s = "";
                break;
            }
        }
        return s;
    }

    public static DBEngineTagText get(final String tag) {
        DBEngineTagText tt = null;
        tt = DBEngineTagText.hashBuffer.get(tag);
        if (tt == null) {
            tt = getDB(tag);
        }
        return tt;
    }

    private static DBEngineTagText getDB(final String tag) {
        DBEngineTagText tt = new DBEngineTagText();
        final String command = "SELECT * FROM GDC_TAGTEXT WHERE TAG = ? ";
        try (final Connection conn = GDDBData.getConnection();
             final PreparedStatement ps = conn.prepareStatement(command)) {
            ps.setString(1, tag);
            try (final ResultSet rs = ps.executeQuery()) {
                final List<DBEngineTagText> list = wrap(rs);
                if (list.isEmpty()) {
                    tt = null;
                } else {
                    tt = list.get(0);
                }
                conn.commit();
            } catch (SQLException ex) {
                throw ex;
            }
        } catch (SQLException ex2) {
            GDMsgLogger.addError(GDMsgFormatter.getString(GDMsgFormatter.rbMsg, "ERR_READ_CONFIG_PLAYER"));
            GDMsgLogger.addError(ex2);
            tt = null;
        }
        return tt;
    }

    public void insert() throws SQLException {
        final String insert = "INSERT INTO GDC_TAGTEXT VALUES (?,?,?,?,?,?,?)";
        try (final Connection conn = GDDBData.getConnection()) {
            final boolean auto = conn.getAutoCommit();
            conn.setAutoCommit(false);
            try (final PreparedStatement ps = conn.prepareStatement(insert)) {
                ps.setString(1, this.tag);
                ps.setString(2, this.textMS);
                ps.setString(3, this.textFS);
                ps.setString(4, this.textNS);
                ps.setString(5, this.textMP);
                ps.setString(6, this.textFP);
                ps.setString(7, this.textNP);
                ps.executeUpdate();
                ps.close();
                conn.commit();
            } catch (SQLException ex) {
                conn.rollback();
                GDMsgLogger.addError(GDMsgFormatter.getString(GDMsgFormatter.rbMsg, "ERR_IN_PLAYER_CONFIG"));
                GDMsgLogger.addError(ex);
            } finally {
                conn.setAutoCommit(auto);
            }
        }
    }

    public static void collectTags(final ARCList list) {
        DBEngineTagText tt = null;
        for (int i = 1; i <= 80; ++i) {
            final String num1 = String.format("%02d", i);
            final String tag1 = "tagSkillClassName" + num1;
            String text = list.getTag(ARCDecompress.FileModule.All, GDConstants.TAG_TEXT_SKILLS, tag1, false);
            if (text != null && !text.isEmpty()) {
                tt = new DBEngineTagText(tag1, text);
                DBEngineTagText.texts.add(tt);
                for (int j = 2; j <= 80; ++j) {
                    final String num2 = String.format("%02d", j);
                    final String tag2 = tag1 + num2;
                    text = list.getTag(ARCDecompress.FileModule.All, GDConstants.TAG_TEXT_SKILLS, tag2, false);
                    if (text != null && !text.isEmpty()) {
                        tt = new DBEngineTagText(tag2, text);
                        DBEngineTagText.texts.add(tt);
                    }
                }
            }
        }
    }

    public static boolean storeTags() {
        boolean success = true;
        for (final DBEngineTagText tt : DBEngineTagText.texts) {
            try {
                tt.insertMod();
            } catch (SQLException ex) {
                success = false;
            }
        }
        DBEngineTagText.texts.clear();
        return success;
    }

    public void insertMod() throws SQLException {
        final DBEngineTagText text = get(this.tag);
        if (text != null) {
            delete(this.tag);
        }
        this.insert();
    }
}
